<!doctype html>
<html lang="en">
	<head>
		<title>Perlin noise | Fireball explosion</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			*{ box-sizing: border-box; margin: 0; padding: 0 }
			body {
				color: #ffffff;
				font-family: tahoma;
				font-size:13px;
				background-color: #222;
				margin: 0px;
				overflow: hidden;

				background: #7d7e7d; /* Old browsers */
				background: -moz-radial-gradient(center, ellipse cover,  #7d7e7d 0%, #0e0e0e 100%); /* FF3.6+ */
				background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#7d7e7d), color-stop(100%,#0e0e0e)); /* Chrome,Safari4+ */
				background: -webkit-radial-gradient(center, ellipse cover,  #7d7e7d 0%,#0e0e0e 100%); /* Chrome10+,Safari5.1+ */
				background: -o-radial-gradient(center, ellipse cover,  #7d7e7d 0%,#0e0e0e 100%); /* Opera 12+ */
				background: -ms-radial-gradient(center, ellipse cover,  #7d7e7d 0%,#0e0e0e 100%); /* IE10+ */
				background: radial-gradient(ellipse at center,  #7d7e7d 0%,#0e0e0e 100%); /* W3C */
				filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7d7e7d', endColorstr='#0e0e0e',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */

			}
			#info{ position: absolute; left: 10px; top: 10px; opacity: .5;  }
			p{ line-height: 1.4em; margin-bottom: 1em; }
			#info:hover{ opacity: 1 }
			a{ color: white; text-shadow: 0 1px 0 rgba( 0,0,0,.5 ) }
		</style>
	</head>
	<body>

		<div id="container"></div>
		<div id="info">
		<p><b>Fireball</b> | Click and drag to rotate, mouse wheel to zoom.<br/>
		Using <a href="https://github.com/ashima/webgl-noise" >WebGL Noise</a>, <a href="https://github.com/evanw/webgl-filter" >random function</a> and <a href="https://github.com/mrdoob/three.js">three.js</a></p>
		<p><a class="button" href="http://www.clicktorelease.com/blog/experiments-with-perlin-noise" >More experiments with Perlin noise</a></p>
		<p><a class="button" href="http://www.clicktorelease.com/blog/vertex-displacement-noise-3d-webgl-glsl-three-js" >Vertex displacement using GLSL</a></p>
	</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
<script src="js/OrbitControls.js"></script>

<script type="x-shader/x-vertex" id="vertexShader">

//
// GLSL textureless classic 3D noise "cnoise",
// with an RSL-style periodic variant "pnoise".
// Author:  Stefan Gustavson (stefan.gustavson@liu.se)
// Version: 2011-10-11
//
// Many thanks to Ian McEwan of Ashima Arts for the
// ideas for permutation and gradient selection.
//
// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
// Distributed under the MIT license. See LICENSE file.
// https://github.com/ashima/webgl-noise
//

vec3 mod289(vec3 x)
{
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}

vec4 mod289(vec4 x)
{
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}

vec4 permute(vec4 x)
{
  return mod289(((x*34.0)+1.0)*x);
}

vec4 taylorInvSqrt(vec4 r)
{
  return 1.79284291400159 - 0.85373472095314 * r;
}

vec3 fade(vec3 t) {
  return t*t*t*(t*(t*6.0-15.0)+10.0);
}

// Classic Perlin noise
float cnoise(vec3 P)
{
  vec3 Pi0 = floor(P); // Integer part for indexing
  vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
  Pi0 = mod289(Pi0);
  Pi1 = mod289(Pi1);
  vec3 Pf0 = fract(P); // Fractional part for interpolation
  vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
  vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
  vec4 iy = vec4(Pi0.yy, Pi1.yy);
  vec4 iz0 = Pi0.zzzz;
  vec4 iz1 = Pi1.zzzz;

  vec4 ixy = permute(permute(ix) + iy);
  vec4 ixy0 = permute(ixy + iz0);
  vec4 ixy1 = permute(ixy + iz1);

  vec4 gx0 = ixy0 * (1.0 / 7.0);
  vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
  gx0 = fract(gx0);
  vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
  vec4 sz0 = step(gz0, vec4(0.0));
  gx0 -= sz0 * (step(0.0, gx0) - 0.5);
  gy0 -= sz0 * (step(0.0, gy0) - 0.5);

  vec4 gx1 = ixy1 * (1.0 / 7.0);
  vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
  gx1 = fract(gx1);
  vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
  vec4 sz1 = step(gz1, vec4(0.0));
  gx1 -= sz1 * (step(0.0, gx1) - 0.5);
  gy1 -= sz1 * (step(0.0, gy1) - 0.5);

  vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
  vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
  vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
  vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
  vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
  vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
  vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
  vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);

  vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
  g000 *= norm0.x;
  g010 *= norm0.y;
  g100 *= norm0.z;
  g110 *= norm0.w;
  vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
  g001 *= norm1.x;
  g011 *= norm1.y;
  g101 *= norm1.z;
  g111 *= norm1.w;

  float n000 = dot(g000, Pf0);
  float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
  float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
  float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
  float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
  float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
  float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
  float n111 = dot(g111, Pf1);

  vec3 fade_xyz = fade(Pf0);
  vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
  vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
  float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
  return 2.2 * n_xyz;
}

// Classic Perlin noise, periodic variant
float pnoise(vec3 P, vec3 rep)
{
  vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
  vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
  Pi0 = mod289(Pi0);
  Pi1 = mod289(Pi1);
  vec3 Pf0 = fract(P); // Fractional part for interpolation
  vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
  vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
  vec4 iy = vec4(Pi0.yy, Pi1.yy);
  vec4 iz0 = Pi0.zzzz;
  vec4 iz1 = Pi1.zzzz;

  vec4 ixy = permute(permute(ix) + iy);
  vec4 ixy0 = permute(ixy + iz0);
  vec4 ixy1 = permute(ixy + iz1);

  vec4 gx0 = ixy0 * (1.0 / 7.0);
  vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
  gx0 = fract(gx0);
  vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
  vec4 sz0 = step(gz0, vec4(0.0));
  gx0 -= sz0 * (step(0.0, gx0) - 0.5);
  gy0 -= sz0 * (step(0.0, gy0) - 0.5);

  vec4 gx1 = ixy1 * (1.0 / 7.0);
  vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
  gx1 = fract(gx1);
  vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
  vec4 sz1 = step(gz1, vec4(0.0));
  gx1 -= sz1 * (step(0.0, gx1) - 0.5);
  gy1 -= sz1 * (step(0.0, gy1) - 0.5);

  vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
  vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
  vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
  vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
  vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
  vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
  vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
  vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);

  vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
  g000 *= norm0.x;
  g010 *= norm0.y;
  g100 *= norm0.z;
  g110 *= norm0.w;
  vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
  g001 *= norm1.x;
  g011 *= norm1.y;
  g101 *= norm1.z;
  g111 *= norm1.w;

  float n000 = dot(g000, Pf0);
  float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
  float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
  float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
  float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
  float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
  float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
  float n111 = dot(g111, Pf1);

  vec3 fade_xyz = fade(Pf0);
  vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
  vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
  float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
  return 2.2 * n_xyz;
}

	varying vec2 vUv;
	varying vec3 vReflect;
	varying vec3 pos;
	varying float ao;
	uniform float time;
	uniform float weight;
	varying float d;

	float stripes( float x, float f) {
		float PI = 3.14159265358979323846264;
		float t = .5 + .5 * sin( f * 2.0 * PI * x);
		return t * t - .5;
	}

	float turbulence( vec3 p ) {
		float w = 100.0;
		float t = -.5;
		for (float f = 1.0 ; f <= 10.0 ; f++ ){
			float power = pow( 2.0, f );
			t += abs( pnoise( vec3( power * p ), vec3( 10.0, 10.0, 10.0 ) ) / power );
		}
		return t;
	}

	void main() {

		vUv = uv;

		vec4 mPosition = modelMatrix * vec4( position, 1.0 );
		vec3 nWorld = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
		vReflect = normalize( reflect( normalize( mPosition.xyz - cameraPosition ), nWorld ) );

		pos = position;
		float noise = turbulence( .5 * normal + time );

		float displacement = - weight * ( 10.0 *  -.10 * noise );
		displacement += 5.0 * pnoise( 0.05 * position + vec3( 2.0 * time ), vec3( 100.0 ) );

		ao = noise;
		//ao = turbulence( .5 * normal + time + 10. * sin( .001 * time ) );
		vec3 newPosition = position + normal * vec3( displacement );
		gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );

	}

	</script>

	<script type="x-shader/x-vertex" id="fragmentShader">

	varying vec2 vUv;
	uniform sampler2D tExplosion;
	varying vec3 vReflect;
	varying vec3 pos;
	varying float ao;
	varying float d;
	float PI = 3.14159265358979323846264;

	float random(vec3 scale,float seed){return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}

	void main() {

		float v = ( 1.1 * ao + 1. ) / 1.1;
		vec3 color = texture2D( tExplosion, vec2( .5, v + .01 * random(vec3(12.9898,78.233,151.7182), 0. ) ) ).rgb;
		gl_FragColor = vec4( color.rgb, 1.0 );

	}

	</script>

	<script type="x-shader/x-vertex" id="vertexShader">

	varying vec2 vUv;

	void main() {

		vUv = uv;
		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

	}

	</script>

	<script type="x-shader/x-vertex" id="fs_Gradient">

	uniform vec2 resolution;
	varying vec2 vUv;

	float random(vec3 scale,float seed){return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}

	void main(void) {

		vec2 p = gl_FragCoord.xy / resolution.xy;
		vec2 d = .5 - p;
		float distance = length( d );
		float dist = 1. - abs( distance );
		dist = pow( dist, 5. );

		vec3 color = vec3( mix( 14., 125., clamp( dist, 0., 1. ) ) / 125. );
		float n = .01 * random( vec3( gl_FragCoord.xy,151.7182), 0. );
		color.rgb += n;

		gl_FragColor = vec4( color, 1.0 );

	}

	</script>

<script>

var container, renderer, scene, camera, mesh;
var start = Date.now();
var fov = 30;

window.addEventListener( 'load', init );

function init() {

	container = document.getElementById( 'container' );

	scene = new THREE.Scene();
	bkgScene = new THREE.Scene();

	camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 10000 );
	camera.position.z = 100;
	camera.target = new THREE.Vector3( 0, 0, 0 );

	scene.add( camera );

	bkgCamera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, -1000, 1000 );

	var bkgShader = new THREE.ShaderMaterial( {

		uniforms: {
			resolution: { type: "v2", value: new THREE.Vector2( window.innerWidth, window.innerHeight ) }
		},
		vertexShader: document.getElementById( 'vertexShader' ).textContent,
		fragmentShader: document.getElementById( 'fs_Gradient' ).textContent,

		depthWrite: false,
		depthTest: false

	} );

	quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 1, 1 ), bkgShader );
	bkgScene.add( quad );

	material = new THREE.ShaderMaterial( {

		uniforms: {
			tExplosion: { type: "t", value: new THREE.TextureLoader().load( 'texture/explosion.png' ) },
			time: { type: "f", value: 0.0 },
			weight: { type: "f", value: 10.0 }
		},
		vertexShader: document.getElementById( 'vertexShader' ).textContent,
		fragmentShader: document.getElementById( 'fragmentShader' ).textContent

	} );

	mesh = new THREE.Mesh( new THREE.IcosahedronBufferGeometry( 20, 5 ), material );
	scene.add( mesh );

	renderer = new THREE.WebGLRenderer( { antialias: true });
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.autoClear = false;

	container.appendChild( renderer.domElement );

	controls = new THREE.OrbitControls( camera, renderer.domElement );

	window.addEventListener( 'resize', onWindowResize, false );

	onWindowResize();
	render();

}

function onWindowResize() {

	var w = window.innerWidth;
	var h = window.innerHeight;

	renderer.setSize( w, h );
	camera.aspect = w / h;
	camera.updateProjectionMatrix();

	var dPR = renderer.getPixelRatio();
	quad.material.uniforms.resolution.value.set( w * dPR, h * dPR );

	quad.scale.set( w, h, 1 );
	bkgCamera.left   = - w / 2;
	bkgCamera.right  =   w / 2;
	bkgCamera.top    =   h / 2;
	bkgCamera.bottom = - h / 2;
	bkgCamera.updateProjectionMatrix();

}

function render() {

	material.uniforms[ 'time' ].value = .00025 * ( Date.now() - start );

	// renderer.clear( true, true, true );  //默认都是true
	renderer.render( bkgScene, bkgCamera );
	renderer.render( scene, camera );

	// requestAnimationFrame( render );
	renderer.setAnimationLoop(render);

}

</script>

	</body>
</html>
